package cn.hhit.common.util;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.apache.struts2.ServletActionContext;

import sun.misc.BASE64Encoder;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;

public class DocumentHandler {

	public Configuration cfg = null;

	public Configuration getConfiguration() {
		if (null == cfg) {
			cfg = new Configuration();
			// 这里有三种方式读取
			// （一个文件目录）
			// cfg.setDirectoryForTemplateLoading(new File("templates"));
			// classpath下的一个目录（读取jar文件）
			// cfg.setClassForTemplateLoading(this.getClass(),
			// "/resourses/templates");
			// 相对web的根路径来说 根目录
			cfg.setServletContextForTemplateLoading(ServletActionContext.getServletContext(), "/templates");
			// setEncoding这个方法一定要设置国家及其编码，不然在flt中的中文在生成html后会变成乱码
			cfg.setEncoding(Locale.getDefault(), "UTF-8");

			// 设置对象的包装器
			cfg.setObjectWrapper(new DefaultObjectWrapper());
			// 设置异常处理器//这样的话就可以${a.b.c.d}即使没有属性也不会出错
			cfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);

		}

		return cfg;
	}

	/**
	 * 以下载的方式生成word，自定义路径
	 * 
	 * @param dataMap
	 * @param out
	 */
	public boolean createDoc(String ftl, Map<String, Object> dataMap, Writer out) {
		try {
			Configuration cfg = getConfiguration();
			Template template = cfg.getTemplate(ftl);
			template.setEncoding("UTF-8");
			template.process(dataMap, out);
		} catch (TemplateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return true;
	}

	/**
	 * 传入数据 可直接本地生成word
	 * 
	 * @param dataMap
	 */
	public void createDoc(String ftl, Map<String, Object> dataMap) {
		// 输出文档路径及名称
		File outFile = new File("G:/wordExport/'" + Math.random() * 10000 + "'report.doc");
		Writer out = null;
		try {
			out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
		} catch (Exception e1) {
			e1.printStackTrace();
		}

		try {
			Configuration cfg = getConfiguration();
			Template template = cfg.getTemplate(ftl);
			template.setEncoding("UTF-8");
			template.process(dataMap, out);
			out.close();
		} catch (TemplateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 
	 * 注意dataMap里存放的数据Key值要与模板中的参数相对应
	 * 
	 * @param dataMap
	 */
	private Map<String, Object> getData() {
		Map<String, Object> dataMap = new HashMap<String, Object>();
		// Map<String, Object> map1 = new HashMap<String, Object>();
		// Map<String, Object> map2 = new HashMap<String, Object>();

		dataMap.put("phase", "软件需求分析");
		dataMap.put("identify", "XMJZ_BG_01");
		dataMap.put("overview",
				"描述项目所属阶段，概况描述姓名整体进展状况。进展状况主要包括：工程活动是否全部完成，是否存在未解决的技术问题；用简洁语言概述章节2中各方面情况，给出项目进展情况的整体评价结论。<w:br/>各阶段项目进展报告主要针对本阶段情况进行分析，项目结束时的项目进展报告应针对项目整个研发周期的情况进行综合分析。");
		// String img1 = getImageStr("H:/Tulips.jpg");
		// map1.put("image", img1);
		// map1.put("i", 1);// 标识图片
		dataMap.put("projectScheduleFx",
				"进度偏离原因：过程不熟悉；人员出差；实际工作量与估计工作量偏差较大；实际生产率高于或低于估计生产率；由于其工作的影响，每天实际投入时间多余或少于计划制定时估计的投入时间；所级里程碑评审或文档评审时间未能按计划进行，有较大延迟；遇到了某种技术问题，解决时间超预期等等。影响分析：应结合挣值法预测的整体进度偏差进行，主要考虑对后续里程碑节点进度的影响。当前进度超差但预测的总进度不超差时，说明对里程碑节点进度影响不大，通常可调整细化计划，通过增加人员、加班等措施弥补。当两者均超差时，说明对里程碑节点进度影响较大，如采取增加人员、加班等措施仍不能弥补的话，应修订总体计划。解决措施为：当进度超差时必须采取措施，具体措施应根据影响分析结果及偏差的实际天数确定。常见的措施为增加人员、晚上或周末加班、修订计划、任务分包等。");
		dataMap.put("scheduleYy",
				"过程不熟悉；人员出差；实际工作量与估计工作量偏差较大；实际生产率高于或低于估计生产率；由于其工作的影响，每天实际投入时间多余或少于计划制定时估计的投入时间；所级里程碑评审或文档评审时间未能按计划进行，有较大延迟；遇到了某种技术问题，解决时间超预期等等。");
		dataMap.put("scheduleFx",
				"应结合挣值法预测的整体进度偏差进行，主要考虑对后续里程碑节点进度的影响。当前进度超差但预测的总进度不超差时，说明对里程碑节点进度影响不大，通常可调整细化计划，通过增加人员、加班等措施弥补。当两者均超差时，说明对里程碑节点进度影响较大，如采取增加人员、加班等措施仍不能弥补的话，应修订总体计划。");
		dataMap.put("scheduleCs", "当进度超差时必须采取措施，具体措施应根据影响分析结果及偏差的实际天数确定。常见的措施为增加人员、晚上或周末加班、修订计划、任务分包等。");
		dataMap.put("workloadYy", "估计偏差大；增加或减少了功能等。");
		dataMap.put("workloadFx",
				"主要看是否影响后续任务分派和项目进度。如果是估计偏差大，对任务分派和进度通常无影响；如果增加或减少了功能，通常会影响任务分派或进度，此时需进一步分析对任务分派和进度的影响程度。");
		dataMap.put("workloadCs", "对任务分派和进度无影响时，不需采取措施；对任务分派或进度有影响时，如果不能作为任务分派依据或进度不能弥补以致可能影响后续里程碑节点了，应重新估计，调整或变更计划。");
		dataMap.put("scaleYy", "估计偏差大；增加或减少了功能等。");
		dataMap.put("scaleFx",
				"主要看是否影响后续任务分派和项目进度。如果是估计偏差大，对任务分派和进度通常无影响；如果增加或减少了功能，通常会影响任务分派或进度，此时需进一步分析对任务分派和进度的影响程度。");
		dataMap.put("scaleCs", "对任务分派和进度无影响时，不需采取措施；对任务分派或进度有影响时，如果不能作为任务分派依据或进度不能弥补以致可能影响后续里程碑节点了，应重新估计，调整或变更计划。");
		dataMap.put("projectFx",
				"不需进行偏差和影响分析，结合风险管理与跟踪表的内容进行分析，主要描述下列内容：本阶段是否有风险发生，如果有，描述采取的措施及措施实施效果；本阶段是否有关闭的风险，关闭的原因；目前正在跟踪的主要风险，采取了哪些缓解措施，风险是否有一定缓解，是否有加大的趋势等；下阶段可能新增的风险（新识别的风险）。");
		dataMap.put("configCheck", "是否发现了问题，发现的问题是否都已解决。问题的主要原因、影响、采取的措施、整改的情况；");
		dataMap.put("configUpdate", "变更的情况，变更了哪些主要配置项，是否按规定变更程序执行，变更后的版本是否受控；");
		dataMap.put("configPlan", "计划受控的配置项是否都已按计划受控，如果有未按计划受控的情况，应说明原因、影响、措施及预期的受控时机，应与定期跟踪报告中内容一致。");
		dataMap.put("benefit",
				"本周期内，计划中规定的利益相关方应参与的活动，是否都已按计划参与？如果已按计划参与，简述参与的效果。如果未按计划参与，简述原因和采取的弥补措施。上述内容应与定期跟踪报告中内容一致。");
		dataMap.put("qualityFx", "使用图形或表格的方式，对项目整个生命周期的产品质量问题进行统计分析。");
		dataMap.put("reviewFx", "使用图形或表格的方式，对项目软件文档评审的问题进行分类分析。");
		dataMap.put("testFx", "使用图形或表格的方式，对项目软件测试的问题进行分类分析。");
		dataMap.put("solveImprove",
				"对发现的各类产品质量问题，提出相应的解决措施或建议。例如，建议加强需求分析开发的有效性，文档编制时多核对上一级输入文件，对软件研制任务书提出的功能、性能、接口、质量特性等分配需求细致分析，及时与系统工程组人员沟通，提高对需求理解的准确性，保证需求的正确性和可追溯性。同时建议加强对标准的学习，文档编写后认真核对，避免笔误和格式等问题。");
		dataMap.put("problemImprove", "主要描述项目当前存在的软件工程组内部无法解决，需上层（项目经理及以上）关注或解决的问题。应结合章节2中各项内容中存在的问题和风险进行综合分析。");

		return dataMap;
	}

	public String getImageStr(String imgFile) {
		InputStream in = null;
		byte[] data = null;
		try {
			in = new FileInputStream(imgFile);
			data = new byte[in.available()];
			in.read(data);
			in.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		BASE64Encoder encoder = new BASE64Encoder();
		return encoder.encode(data);
	}

	public static void main(String[] args) {
		DocumentHandler word = new DocumentHandler();
		System.out.println("----------------");
		Map<String, Object> map = word.getData();
		System.out.println(map.toString());
		word.createDoc("", map);
	}

}